<?php
	
/*

	gd : class for handling image processing
	
	What follows is an abbreviated version of class.upload by Colin Verot.
	It has been renamed to prevent a naming clash with smuoi's own class upload 
	(this modified version does not handle uploads).
	
	Since the class has only been abbreviated and not added to, I haven't added myself to 
	a list of contributors and Colin's copyright notice (below) is exactly as I found it.
	
	The original class comes with a great deal of extra functionality.
	You can get a copy of it along with more of Colin's excellent work
	at verot.net. 

*/	
	
// +------------------------------------------------------------------------+
// | class.upload.php                                                       |
// +------------------------------------------------------------------------+
// | Copyright (c) Colin Verot 2003-2007. All rights reserved.              |
// | Version       0.25                                                     |
// | Last modified 17/11/2007                                               |
// | Email         colin@verot.net                                          |
// | Web           http://www.verot.net                                     |
// +------------------------------------------------------------------------+
// | This program is free software; you can redistribute it and/or modify   |
// | it under the terms of the GNU General Public License version 2 as      |
// | published by the Free Software Foundation.                             |
// |                                                                        |
// | This program is distributed in the hope that it will be useful,        |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of         |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          |
// | GNU General Public License for more details.                           |
// |                                                                        |
// | You should have received a copy of the GNU General Public License      |
// | along with this program; if not, write to the                          |
// |   Free Software Foundation, Inc., 59 Temple Place, Suite 330,          |
// |   Boston, MA 02111-1307 USA                                            |
// |                                                                        |
// | Please give credit on sites that use class.upload and submit changes   |
// | of the script so other people can use them as well.                    |
// | This script is free to use, don't abuse.                               |
// +------------------------------------------------------------------------+
//
	
	class gd{
	
		/**
		 * Uploaded file name
		 */
		var $file_src_name;
	
		/**
		 * Uploaded file name body (i.e. without extension)
		 */
		var $file_src_name_body;
	
		/**
		 * Uploaded file name extension
		 */
		var $file_src_name_ext;
	
		/**
		 * Uploaded file MIME type
		 */
		var $file_src_mime;
	
		/**
		 * Uploaded file size, in bytes
		 */
		var $file_src_size;
	
		/**
		 * Uloaded file name, including server path
	
		 */
		var $file_src_pathname;
	
		/**
		 * Destination file name
		 */
		var $file_dst_path;
	
		/**
		 * Destination file name
		 */
		var $file_dst_name;
	
		/**
		 * Destination file name body (i.e. without extension)
		 */
		var $file_dst_name_body;
	
		/**
		 * Destination file extension
		 */
		var $file_dst_name_ext;
	
		/**
		 * Destination file name, including path
		 */
		var $file_dst_pathname;
	
		/**
		 * Source image width
		 */
		var $image_src_x;
	
		/**
		 * Source image height
		 */
		var $image_src_y;
	
		/**
		 * Source image color depth
		 */
		var $image_src_bits;
	
		/**
		 * Number of pixels
		 */
		var $image_src_pixels;
	
		/**
		 * Type of image (png, gif, jpg or bmp)
		 */
		var $image_src_type;
	
		/**
		 * Destination image width
		 */
		var $image_dst_x;
	
		/**
		 * Destination image height
		 */
		var $image_dst_y;
	
		/**
		 * Supported image formats
		 */
		var $image_supported;
	
		/**
		 * Flag set after calling a process
		 */
		var $processed;
	
		/**
		 * Set this variable to replace the name body (i.e. without extension)
		 */
		var $file_new_name_body;
	
		/**
		 * Set this variable to change the file extension
		 */
		var $file_new_name_ext;
	
		/**
		 * Set this variable tu true to allow overwriting of an existing file
		 */
		var $file_overwrite;
	
		/**
		 * Set this variable to true to resize the file if it is an image
		 *
		 * You will probably want to set {@link image_x} and {@link image_y}, and maybe one of the ratio variables
		 */
		var $image_resize;
	
		/**
		 * Set this variable to convert the file if it is an image
		 *
		 * Possibles values are : ''; 'png'; 'jpeg'; 'gif'; 'bmp'
		 *
		 * Default value is '' (no conversion)<br>
		 * If {@link resize} is true, {@link convert} will be set to the source file extension 
		 */
		var $image_convert;
	
		/**
		 * Set this variable to the wanted (or maximum/minimum) width for the processed image, in pixels
		 *
		 * Default value is 150
		 */
		var $image_x;
	
		/**
		 * Set this variable to the wanted (or maximum/minimum) height for the processed image, in pixels
		 *
		 * Default value is 150
		 */
		var $image_y;
	
		/**
		 * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}
		 *
		 * Default value is false
		 */
		var $image_ratio;
	
		/**
		 * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}
		 * 
		 * The image will be resized as to fill the whole space, and excedent will be cropped
		 *
		 * Value can also be a string, one or more character from 'TBLR' (top, bottom, left and right)
		 * If set as a string, it determines which side of the image is kept while cropping.
		 * By default, the part of the image kept is in the center, i.e. it crops equally on both sides
		 *
		 * Default value is false
		 */
		var $image_ratio_crop;
	
		/**
		 * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}
		 * 
		 * The image will be resized to fit entirely in the space, and the rest will be colored.
		 * The default color is white, but can be set with {@link image_default_color}
		 *
		 * Value can also be a string, one or more character from 'TBLR' (top, bottom, left and right)
		 * If set as a string, it determines in which side of the space the image is displayed.
		 * By default, the image is displayed in the center, i.e. it fills the remaining space equally on both sides
		 *
		 * Default value is false
		 */
		var $image_ratio_fill;
	
		/**
		 * Set this variable to a number of pixels so that {@link image_x} and {@link image_y} are the best match possible
		 * 
		 * The image will be resized to have approximatively the number of pixels
		 * The aspect ratio wil be conserved
		 *
		 * Default value is false
		 */
		var $image_ratio_pixels;
	
		/**
		 * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}, 
		 * but only if original image is bigger
		 *
		 * Default value is false
		 */
		var $image_ratio_no_zoom_in;
	
		/**
		 * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}, 
		 * but only if original image is smaller
		 *
		 * Default value is false
		 */
		var $image_ratio_no_zoom_out;
	
		/**
		 * Set this variable to calculate {@link image_x} automatically , using {@link image_y} and conserving ratio
		 *
		 * Default value is false
		 */
		var $image_ratio_x;
	
		/**
		 * Set this variable to calculate {@link image_y} automatically , using {@link image_x} and conserving ratio
		 *
		 * Default value is false
		 */
		var $image_ratio_y;
	
		/**
		 * Quality of JPEG created/converted destination image
		 *
		 * Default value is 85
		 */
		var $jpeg_quality;
	
		/**
		 * Determines the quality of the JPG image to fit a desired file size
		 *
		 * Value is in bytes. The JPG quality will be set between 1 and 100%
		 * The calculations are approximations.
		 *
		 * Default value is null (no calculations)
		 */
		var $jpeg_size;
		
		/**
		 * Flag set to true when the image is transparent
		 *
		 * This is actually used only for transparent GIFs 
		 */
		var $image_is_transparent;
		
		/**
		 * Transparent color in a palette
		 *
		 * This is actually used only for transparent GIFs 
		 */
		var $image_transparent_color;
	
		/**
		 * Background color, used to paint transparent areas with
		 *
		 * If set, it will forcibly remove transparency by painting transparent areas with the color
		 * This setting will fill in all transparent areas in PNG and GIF, as opposed to {@link image_default_color}
		 * which will do so only in BMP, JPEG, and alpha transparent areas in transparent GIFs
		 * This setting overrides {@link image_default_color}
		 */
		var $image_background_color;   
		
		/**
		 * Default color for non alpha-transparent images
		 *
		 * This setting is to be used to define a background color for semi transparent areas
		 * of an alpha transparent when the output format doesn't support alpha transparency
		 * This is useful when, from an alpha transparent PNG image, or an image with alpha transparent features
		 * if you want to output it as a transparent GIFs for instance, you can set a blending color for transparent areas
		 * If you output in JPEG or BMP, this color will be used to fill in the previously transparent areas
		 *
		 * The default color white
		 */
		var $image_default_color;
			
		/**
		 * Flag set to true when the image is not true color
		 */
		var $image_is_palette;    
		
		/**
		 * Corrects the image brightness
		 *
		 * Value can range between -127 and 127
		 *
		 * Default value is null
	 
		 */
		var $image_brightness;
	
		/**
		 * Corrects the image contrast
		 */
		var $image_contrast;
		
		/**
		 * Applies threshold filter
		 *
		 * Value can range between -127 and 127
		 *
		 * Default value is null
		 */
		var $image_threshold;
	
		/**
		 * Applies a tint on the image
		 *
		 * Value is an hexadecimal color, such as #FFFFFF
		 *
		 * Default value is null
		 */
		var $image_tint_color;
	
		/**
		 * Applies a colored overlay on the image
		 *
		 * Value is an hexadecimal color, such as #FFFFFF
		 *
		 * To use with {@link image_overlay_percent}
		 *
		 * Default value is null
		 */
		var $image_overlay_color;
	
		/**
		 * Sets the percentage for the colored overlay
		 *
		 * Value is a percentage, as an integer between 0 and 100
		 *
		 * Unless used with {@link image_overlay_color}, this setting has no effect
		 *
		 * Default value is 50
		 */
		var $image_overlay_percent;
	
		/**
		 * Inverts the color of an image
		 *
		 * Default value is FALSE
		 */
		var $image_negative;
		
		/**
		 * Turns the image into greyscale
		 *
		 * Default value is FALSE
		 */
		var $image_greyscale;
	
		/**
		 * Adds a text label on the image
		 *
		 * Value is a string, any text. Text will not word-wrap, although you can use breaklines in your text "\n"
		 *
		 * If set, this setting allow the use of all other settings starting with image_text_
		 *
		 * Default value is null
		 */
		var $image_text;
	
		/**
		 * Sets the text direction for the text label
		 *
		 * Value is either 'h' or 'v', as in horizontal and vertical
		 *
		 * Default value is h (horizontal)
		 *
		 * @access public
		 * @var string;
		 */
		var $image_text_direction;
	
		/**
		 * Sets the text color for the text label
		 *
		 * Value is an hexadecimal color, such as #FFFFFF
		 *
		 * Default value is #FFFFFF (white)
		 */
		var $image_text_color;
	
		/**
		 * Sets the text visibility in the text label
		 *
		 * Value is a percentage, as an integer between 0 and 100
		 *
		 * Default value is 100
		 */
		var $image_text_percent;
	
		/**
		 * Sets the text background color for the text label
		 *
		 * Value is an hexadecimal color, such as #FFFFFF
		 *
		 * Default value is null (no background)
		 */
		var $image_text_background;
	
		/**
		 * Sets the text background visibility in the text label
		 *
		 * Value is a percentage, as an integer between 0 and 100
		 *
		 * Default value is 100
		 */
		var $image_text_background_percent;
	
		/**
		 * Sets the text font in the text label
		 *
		 * Value is a an integer between 1 and 5 for GD built-in fonts. 1 is the smallest font, 5 the biggest
		 * Value can also be a string, which represents the path to a GDF font. The font will be loaded into GD, and used as a built-in font.
		 *
		 * Default value is 5
		 */
		var $image_text_font;
	
		/**
		 * Sets the text label position within the image
		 *
		 * Value is one or two out of 'TBLR' (top, bottom, left, right)
		 *
		 * The positions are as following:   
		 * <pre>
		 *                        TL  T  TR
		 *                        L       R
		 *                        BL  B  BR
		 * </pre>
		 *
		 * Default value is null (centered, horizontal and vertical)
		 *
		 * Note that is {@link image_text_x} and {@link image_text_y} are used, this setting has no effect
		 */
		var $image_text_position;
	
		/**
		 * Sets the text label absolute X position within the image
		 *
		 * Value is in pixels, representing the distance between the left of the image and the label
		 * If a negative value is used, it will represent the distance between the right of the image and the label    
		 *     
		 * Default value is null (so {@link image_text_position} is used)
		 */
		var $image_text_x;
	
		/**
		 * Sets the text label absolute Y position within the image
		 *
		 * Value is in pixels, representing the distance between the top of the image and the label
		 * If a negative value is used, it will represent the distance between the bottom of the image and the label    
		 *     
		 * Default value is null (so {@link image_text_position} is used)
		 */
		var $image_text_y;
	
		/**
		 * Sets the text label padding
		 *
		 * Value is in pixels, representing the distance between the text and the label background border
		 *     
		 * Default value is 0
		 *
		 * This setting can be overriden by {@link image_text_padding_x} and {@link image_text_padding_y}
		 */
		var $image_text_padding;
	
		/**
		 * Sets the text label horizontal padding
		 *
		 * Value is in pixels, representing the distance between the text and the left and right label background borders
		 *     
		 * Default value is null
		 *
		 * If set, this setting overrides the horizontal part of {@link image_text_padding}
		 */
		var $image_text_padding_x;
	
		/**
		 * Sets the text label vertical padding
		 *
		 * Value is in pixels, representing the distance between the text and the top and bottom label background borders
		 *     
		 * Default value is null
		 *
		 * If set, his setting overrides the vertical part of {@link image_text_padding}
		 */
		var $image_text_padding_y;
	
		/**
		 * Sets the text alignment
		 *
		 * Value is a string, which can be either 'L', 'C' or 'R'
		 *     
		 * Default value is 'C'
		 *
		 * This setting is relevant only if the text has several lines.
		 */
		var $image_text_alignment;
	
		/**
		 * Sets the text line spacing
		 *
		 * Value is an integer, in pixels
		 *     
		 * Default value is 0
		 *
		 * This setting is relevant only if the text has several lines.
		 */
		var $image_text_line_spacing;
		
		/**
		 * Flips the image vertically or horizontally
		 *
		 * Value is either 'h' or 'v', as in horizontal and vertical
		 *
		 * Default value is null (no flip)
		 *
		 * @access public
		 * @var string;
		 */
		var $image_flip;
	
		/**
		 * Rotates the image by increments of 45 degrees
		 *
		 * Value is either 90, 180 or 270
		 *
		 * Default value is null (no rotation)
		 *
		 * @access public
		 * @var string;
		 */
		var $image_rotate;
	
		/**
		 * Crops an image
		 *
		 * Values are four dimensions, or two, or one (CSS style)
		 * They represent the amount cropped top, right, bottom and left.
		 * These values can either be in an array, or a space separated string.
		 * Each value can be in pixels (with or without 'px'), or percentage (of the source image)
		 *
		 * For instance, are valid:
		 * <pre>
		 * $foo->image_crop = 20                  OR array(20);
		 * $foo->image_crop = '20px'              OR array('20px');
		 * $foo->image_crop = '20 40'             OR array('20', 40);
		 * $foo->image_crop = '-20 25%'           OR array(-20, '25%');
		 * $foo->image_crop = '20px 25%'          OR array('20px', '25%');
		 * $foo->image_crop = '20% 25%'           OR array('20%', '25%');
		 * $foo->image_crop = '20% 25% 10% 30%'   OR array('20%', '25%', '10%', '30%');
		 * $foo->image_crop = '20px 25px 2px 2px' OR array('20px', '25%px', '2px', '2px');
		 * $foo->image_crop = '20 25% 40px 10%'   OR array(20, '25%', '40px', '10%');
		 * </pre>
		 *
		 * If a value is negative, the image will be expanded, and the extra parts will be filled with black
		 *
		 * Default value is null (no cropping)
		 */
		var $image_crop;
	
		/**
		 * Adds a single-color border on the outer of the image
		 *
		 * Values are four dimensions, or two, or one (CSS style)
		 * They represent the border thickness top, right, bottom and left.
		 * These values can either be in an array, or a space separated string.
		 * Each value can be in pixels (with or without 'px'), or percentage (of the source image)
		 *
		 * See {@link image_crop} for valid formats
		 *
		 * If a value is negative, the image will be cropped. 
		 * Note that the dimensions of the picture will be increased by the borders' thickness
		 *
		 * Default value is null (no border)
		 */
		var $image_border;
	
		/**
		 * Border color
		 *
		 * Value is a color, in hexadecimal format. 
		 * This setting is used only if {@link image_border} is set
		 *
		 * Default value is #FFFFFF
		 */
		var $image_border_color;
		
	
		function init() {
	
			// overiddable variables
			$this->file_new_name_body       = '';       // replace the name body
			$this->file_new_name_ext        = '';       // replace the file extension
			$this->file_overwrite           = false;    // allows overwritting if the file already exists
			
			$this->image_resize             = false;    // resize the image
			$this->image_convert            = '';       // convert. values :''; 'png'; 'jpeg'; 'gif'; 'bmp'
	
			$this->image_x                  = 150;
			$this->image_y                  = 150;
			$this->image_ratio              = false;    // keeps aspect ratio with x and y dimensions
			$this->image_ratio_crop         = false;    // keeps aspect ratio with x and y dimensions, filling the space
			$this->image_ratio_fill         = false;    // keeps aspect ratio with x and y dimensions, fitting the image in the space, and coloring the rest
			$this->image_ratio_pixels       = false;    // keeps aspect ratio, calculating x and y so that the image is approx the set number of pixels
			$this->image_ratio_no_zoom_in   = false;
			$this->image_ratio_no_zoom_out  = false;
			$this->image_ratio_x            = false;    // calculate the $image_x if true
			$this->image_ratio_y            = false;    // calculate the $image_y if true
			$this->jpeg_quality             = 85;
			$this->jpeg_size                = null;
			$this->image_is_transparent     = false;
			$this->image_transparent_color  = null;
			$this->image_background_color   = null;
			$this->image_default_color      = '#ffffff';
			$this->image_is_palette         = false;
	
			$this->image_brightness         = null; 
			$this->image_contrast           = null;
			$this->image_threshold          = null;
			$this->image_tint_color         = null;
			$this->image_overlay_color      = null;
			$this->image_overlay_percent    = null;
			$this->image_negative           = false;
			$this->image_greyscale          = false;
	
			$this->image_text               = null;
			$this->image_text_direction     = null;
			$this->image_text_color         = '#FFFFFF';
			$this->image_text_percent       = 100;
			$this->image_text_background    = null;
			$this->image_text_background_percent = 100; 
			$this->image_text_font          = 5;
			$this->image_text_x             = null;
			$this->image_text_y             = null;
			$this->image_text_position      = null; 
			$this->image_text_padding       = 0;
			$this->image_text_padding_x     = null;
			$this->image_text_padding_y     = null;
			$this->image_text_alignment     = 'C';  
			$this->image_text_line_spacing  = 0;
	
			$this->image_flip               = null; 
			$this->image_rotate             = null;   
			$this->image_crop               = null;
	  
			$this->image_border             = null;
			$this->image_border_color       = '#FFFFFF';
		}
	
	 
		function __construct($file){
			
			if(!is_file($file) || !is_readable($file)){
				$this->error = "$file is not readable";
				return false;
			}
	
			$this->file_src_name      = '';
			$this->file_src_name_body = '';
			$this->file_src_name_ext  = '';
			$this->file_src_mime      = '';
			$this->file_src_size      = '';
			$this->file_src_pathname  = '';
			$this->file_src_temp      = '';
	
			$this->file_dst_path      = '';
			$this->file_dst_name      = '';
			$this->file_dst_name_body = '';
			$this->file_dst_name_ext  = '';
			$this->file_dst_pathname  = '';
	
			$this->image_src_x        = null;
			$this->image_src_y        = null;
			$this->image_src_bits     = null;
			$this->image_src_type     = null;
			$this->image_src_pixels   = null;
			$this->image_dst_x        = 0;
			$this->image_dst_y        = 0;
			
			$this->processed          = false;    
			$this->init();
			$info                     = null;
			
			// determines the supported MIME types, and matching image format
			$this->image_supported = array();
			if ($this->gdversion()) {
				if (imagetypes() & IMG_GIF) {
					$this->image_supported['image/gif'] = 'gif';
				}
				if (imagetypes() & IMG_JPG) {
					$this->image_supported['image/jpg'] = 'jpg';
					$this->image_supported['image/jpeg'] = 'jpg';
					$this->image_supported['image/pjpeg'] = 'jpg';
				}
				if (imagetypes() & IMG_PNG) {
					$this->image_supported['image/png'] = 'png';
					$this->image_supported['image/x-png'] = 'png';
				}
				if (imagetypes() & IMG_WBMP) {
					$this->image_supported['image/bmp'] = 'bmp';
					$this->image_supported['image/x-ms-bmp'] = 'bmp';
					$this->image_supported['image/x-windows-bmp'] = 'bmp';
				}
			}
	
			$this->file_src_pathname   = $file;
			$this->file_src_name       = basename($file);
		
			ereg('\.([^\.]*$)', $this->file_src_name, $extension);
			if (is_array($extension)) {
				$this->file_src_name_ext      = strtolower($extension[1]);
				$this->file_src_name_body     = substr($this->file_src_name, 0, ((strlen($this->file_src_name) - strlen($this->file_src_name_ext)))-1);
			} else {
				$this->file_src_name_ext      = '';
				$this->file_src_name_body     = $this->file_src_name;
			}
			$this->file_src_size = filesize($file);
			// we try to retrieve the MIME type
			$info = getimagesize($this->file_src_pathname);
			$this->file_src_mime = (is_array($info) && array_key_exists('mime', $info) ? $info['mime'] : null); 
			// if we don't have a MIME type, we attempt to retrieve it the old way
			if (empty($this->file_src_mime)) {
				$mime = (is_array($info) && array_key_exists(2, $info) ? $info[2] : null); // 1 = GIF, 2 = JPG, 3 = PNG
				$this->file_src_mime = ($mime==IMAGETYPE_GIF ? 'image/gif' : ($mime==IMAGETYPE_JPEG ? 'image/jpeg' : ($mime==IMAGETYPE_PNG ? 'image/png' : ($mime==IMAGETYPE_BMP ? 'image/bmp' : null))));
			}
			// if we still don't have a MIME type, we attempt to retrieve it otherwise
			if (empty($this->file_src_mime) && function_exists('mime_content_type')) {
				$this->file_src_mime = mime_content_type($this->file_src_pathname);
			}                     
			$this->file_src_error = 0; 
			// determine whether the file is an image
			if (array_key_exists($this->file_src_mime, $this->image_supported)) $this->image_src_type = $this->image_supported[$this->file_src_mime];
			else{
				$this->error = $this->file_src_mime.' is not supported';
				return false;
			}
	
			if (is_array($info)) {
				$this->image_src_x    = $info[0];
				$this->image_src_y    = $info[1];   
				$this->image_src_pixels = $this->image_src_x * $this->image_src_y;   
				$this->image_src_bits = array_key_exists('bits', $info) ? $info['bits'] : null;
			}
		}
	
	
		/**
		 * Returns the version of GD
		 *
		 * @access public
		 * @param  boolean  $full Optional flag to get precise version
		 * @return float GD version
		 */
		function gdversion($full = false) {
			static $gd_version;
			static $gd_full_version;
			if ($gd_version === null) {
				if (function_exists('gd_info')) {
					$gd = gd_info();
					$gd = $gd["GD Version"];
					$regex = "/([\d\.]+)/i";
				} else {
					ob_start();
					phpinfo(8);
					$gd = ob_get_contents();
					ob_end_clean();
					$regex = "/\bgd\s+version\b[^\d\n\r]+?([\d\.]+)/i";
				}
				if (preg_match($regex, $gd, $m)) {
					$gd_full_version = (string) $m[1];
					$gd_version = (float) $m[1];
				} else {
					$gd_full_version = 'none';
					$gd_version = 0;
				}
			}
			return $full ? $gd_full_version : $gd_version;
		} 
	
		/**
		 * Creates a container image
		 *
		 * @access private
		 * @param  integer  $x    Width
		 * @param  integer  $y    Height
		 * @param  boolean  $fill Optional flag to draw the background color or not
		 * @param  boolean  $trsp Optional flag to set the background to be transparent
		 * @return resource Container image
		 */
		function imagecreatenew($x, $y, $fill = true, $trsp = false) {
			if ($this->gdversion() >= 2 && !$this->image_is_palette) {
				// create a true color image
				$dst_im = imagecreatetruecolor($x, $y);
				// this preserves transparency in PNGs, in true color
				if (empty($this->image_background_color) || $trsp) {
					imagealphablending($dst_im, false );
					imagefilledrectangle($dst_im, 0, 0, $x, $y, imagecolorallocatealpha($dst_im, 0, 0, 0, 127));
				}
			} else {
				// creates a palette image
				$dst_im = imagecreate($x, $y);
				// preserves transparency for palette images, if the original image has transparency
				if (($fill && $this->image_is_transparent && empty($this->image_background_color)) || $trsp) {        
					imagefilledrectangle($dst_im, 0, 0, $x, $y, $this->image_transparent_color);
					imagecolortransparent($dst_im, $this->image_transparent_color);
				}
			}
			// fills with background color if any is set
			if ($fill && !empty($this->image_background_color) && !$trsp) {
				sscanf($this->image_background_color, "#%2x%2x%2x", $red, $green, $blue);
				$background_color = imagecolorallocate($dst_im, $red, $green, $blue);
				imagefilledrectangle($dst_im, 0, 0, $x, $y, $background_color);
			}
			return $dst_im;
		}
	
	
		/**
		 * Transfers an image from the container to the destination image
		 *
		 * @access private
		 * @param  resource $src_im Container image
		 * @param  resource $dst_im Destination image
		 * @return resource Destination image
		 */
		function imagetransfer($src_im, $dst_im) {
			if (is_resource($dst_im)) imagedestroy($dst_im);     
			$dst_im = & $src_im;
			return $dst_im;
		}
	
		/**
		 * Merges two images
		 *
		 * If the output format is PNG, then we do it pixel per pixel to retain the alpha channel
		 *
		 * @access private
		 * @param  resource $dst_img Destination image
		 * @param  resource $src_img Overlay image
		 * @param  int      $dst_x   x-coordinate of destination point 
		 * @param  int      $dst_y   y-coordinate of destination point 
		 * @param  int      $src_x   x-coordinate of source point 
		 * @param  int      $src_y   y-coordinate of source point 
		 * @param  int      $src_w   Source width 
		 * @param  int      $src_h   Source height 
		 * @param  int      $pct     Optional percentage of the overlay, between 0 and 100 (default: 100)
		 * @return resource Destination image
		 */
		function imagecopymergealpha(&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct = 0) {
			$dst_x = (int) $dst_x;
			$dst_y = (int) $dst_y;
			$src_x = (int) $src_x;
			$src_y = (int) $src_y;
			$src_w = (int) $src_w;
			$src_h = (int) $src_h;
			$pct   = (int) $pct;
			$dst_w = imagesx($dst_im);
			$dst_h = imagesy($dst_im);
	
			for ($y = $src_y; $y < $src_h; $y++) {
				for ($x = $src_x; $x < $src_w; $x++) {
	
					if ($x >= 0 && $x <= $dst_w && $y >= 0 && $y <= $dst_h) {
						$dst_pixel = imagecolorsforindex($dst_im, imagecolorat($dst_im, $x + $dst_x, $y + $dst_y));
						$src_pixel = imagecolorsforindex($src_im, imagecolorat($src_im, $x + $src_x, $y + $src_y));
	
						$src_alpha = 1 - ($src_pixel['alpha'] / 127);
						$dst_alpha = 1 - ($dst_pixel['alpha'] / 127);
						$opacity = $src_alpha * $pct / 100;
						if ($dst_alpha >= $opacity) $alpha = $dst_alpha;
						if ($dst_alpha < $opacity)  $alpha = $opacity;              
						if ($alpha > 1) $alpha = 1;                   
	
						if ($opacity > 0) {
							$dst_red   = round(( ($dst_pixel['red']   * $dst_alpha * (1 - $opacity)) ) );
							$dst_green = round(( ($dst_pixel['green'] * $dst_alpha * (1 - $opacity)) ) );
							$dst_blue  = round(( ($dst_pixel['blue']  * $dst_alpha * (1 - $opacity)) ) );
							$src_red   = round((($src_pixel['red']   * $opacity)) );
							$src_green = round((($src_pixel['green'] * $opacity)) );
							$src_blue  = round((($src_pixel['blue']  * $opacity)) );
							$red   = round(($dst_red   + $src_red  ) / ($dst_alpha * (1 - $opacity) + $opacity));
							$green = round(($dst_green + $src_green) / ($dst_alpha * (1 - $opacity) + $opacity));
							$blue  = round(($dst_blue  + $src_blue ) / ($dst_alpha * (1 - $opacity) + $opacity));
							if ($red   > 255) $red   = 255;  
							if ($green > 255) $green = 255;  
							if ($blue  > 255) $blue  = 255;  
							$alpha =  round((1 - $alpha) * 127);
							$color = imagecolorallocatealpha($dst_im, $red, $green, $blue, $alpha);
							imagesetpixel($dst_im, $x + $dst_x, $y + $dst_y, $color);
						}
					}
				}
			}
			return true;
		}
	
	  
		function process($server_path) {
	
			$this->error        = '';
			$this->processed    = false;
			$return_mode        = false;
			$return_content     = true;
	
			if(!is_dir($server_path) || !is_writable($server_path)){
				$this->error = "no dir at $server_path";
				return false; 
			}
			
			if(substr($server_path, -1) != '/') $server_path .= '/';
			
			if(!$this->gdversion()){
				$this->error = "no gd";
				return false; 
			}
	
			$this->file_dst_path        = $server_path;
	
			// repopulate dst variables from src
			$this->file_dst_name        = $this->file_src_name;
			$this->file_dst_name_body   = $this->file_src_name_body;
			$this->file_dst_name_ext    = $this->image_convert ? $this->image_convert : $this->file_src_name_ext;
	
			if ($this->image_convert != '') { // if we convert as an image
				$this->file_dst_name_ext  = $this->image_convert;
			}
			if ($this->file_new_name_body != '') { // rename file body
				$this->file_dst_name_body = $this->file_new_name_body;
			}
			if ($this->file_new_name_ext != '') { // rename file ext
				$this->file_dst_name_ext  = $this->file_new_name_ext;
			}
	
			// do we do some image manipulation?
			$image_manipulation  = (
				   $this->image_resize 
				|| $this->image_convert != '' 
				|| is_numeric($this->image_brightness) 
				|| is_numeric($this->image_contrast) 
				|| is_numeric($this->image_threshold) 
				|| !empty($this->image_tint_color) 
				|| !empty($this->image_overlay_color) 
				|| !empty($this->image_text)
				|| $this->image_greyscale
				|| $this->image_negative
				|| is_numeric($this->image_rotate)
				|| is_numeric($this->jpeg_size)
				|| !empty($this->image_flip)
				|| !empty($this->image_crop)
				|| !empty($this->image_border)
			);
	
			if ($image_manipulation) {
				if ($this->image_convert=='') {
					$this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : '');
				} else {
					$this->file_dst_name = $this->file_dst_name_body . '.' . $this->image_convert;
				}
			} else {
				$this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : '');
			}
			
			$this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name;
			
			if (!$this->file_overwrite && file_exists($this->file_dst_pathname)){
				$this->error = "file exists";
				return false;
			}
	
			switch($t = $this->image_src_type) {
				case 'jpg':
					$t = 'jpeg';
				case 'png':
				case 'gif':
				case 'bmp':
					if (!function_exists($f = "imagecreatefrom$t")){
						$this->error = "no $t create support";
						return false;
					} 
					$image_src = @$f($this->file_src_pathname);
					if (!$image_src) {
						$this->error = 'create_error';
						return false;
					}
					break;
				default:
					$this->error = 'source_invalid';
					return false;
			}
	
			// we have to set image_convert if it is not already
			if (empty($this->image_convert)) $this->image_convert = in_array($this->file_src_name_ext, $this->image_supported) ? $this->file_src_name_ext : 'png';
	
			// we set the default color to be the background color if we don't output in a transparent format
			if ($this->image_convert != 'png' && $this->image_convert != 'gif' && !empty($this->image_default_color) && empty($this->image_background_color)) $this->image_background_color = $this->image_default_color;
			if (!empty($this->image_background_color)) $this->image_default_color = $this->image_background_color;
			if (empty($this->image_default_color)) $this->image_default_color = '#FFFFFF';
	
			$this->image_src_x = imagesx($image_src);
			$this->image_src_y = imagesy($image_src);
			$this->image_dst_x = $this->image_src_x;
			$this->image_dst_y = $this->image_src_y;
			$gd_version = $this->gdversion();
			$ratio_crop = null;
	
			if (!imageistruecolor($image_src)) {  // $this->image_src_type == 'gif'
				$this->image_is_palette = true;
				$this->image_transparent_color = imagecolortransparent($image_src);
				if ($this->image_transparent_color >= 0 && imagecolorstotal($image_src) > $this->image_transparent_color) {
					$this->image_is_transparent = true;
				} 
				$transparent_color = imagecolortransparent($image_src);
				if ($transparent_color >= 0 && imagecolorstotal($image_src) > $transparent_color) {
					$rgb = imagecolorsforindex($image_src, $transparent_color);
					$transparent_color = ($rgb['red'] << 16) | ($rgb['green'] << 8) | $rgb['blue'];
					imagecolortransparent($image_src, imagecolorallocate($image_src, 0, 0, 0));
				}
				$true_color = imagecreatetruecolor($this->image_src_x, $this->image_src_y);
				imagealphablending($image_src, false);
				imagesavealpha($image_src, true);
				imagecopy($true_color, $image_src, 0, 0, 0, 0, $this->image_src_x, $this->image_src_y);
				$image_src = $this->imagetransfer($true_color, $image_src);
				if ($transparent_color >= 0) {
					imagealphablending($image_src, false);
					imagesavealpha($image_src, true);
					for ($x = 0; $x < $this->image_src_x; $x++) {
						for ($y = 0; $y < $this->image_src_y; $y++) {
							if (imagecolorat($image_src, $x, $y) == $transparent_color) imagesetpixel($image_src, $x, $y, 127 << 24);
						}
					}
				}
				$this->image_is_palette = false;
			}
			
			if ($this->image_resize) {

				if ($this->image_ratio_x) {
					$this->image_dst_x = round(($this->image_src_x * $this->image_y) / $this->image_src_y);
					$this->image_dst_y = $this->image_y;
				} else if ($this->image_ratio_y) {
					$this->image_dst_x = $this->image_x;
					$this->image_dst_y = round(($this->image_src_y * $this->image_x) / $this->image_src_x);
				} else if (is_numeric($this->image_ratio_pixels)) {
					$pixels = $this->image_src_y * $this->image_src_x;
					$diff = sqrt($this->image_ratio_pixels / $pixels);
					$this->image_dst_x = round($this->image_src_x * $diff);
					$this->image_dst_y = round($this->image_src_y * $diff);
				} else if ($this->image_ratio || $this->image_ratio_crop || $this->image_ratio_fill || $this->image_ratio_no_zoom_in || $this->image_ratio_no_zoom_out) {
					if ((!$this->image_ratio_no_zoom_in && !$this->image_ratio_no_zoom_out)
						 || ($this->image_ratio_no_zoom_in && ($this->image_src_x > $this->image_x || $this->image_src_y > $this->image_y))
						 || ($this->image_ratio_no_zoom_out && $this->image_src_x < $this->image_x && $this->image_src_y < $this->image_y)) {
						$this->image_dst_x = $this->image_x;
						$this->image_dst_y = $this->image_y;
						if ($this->image_ratio_crop) {
							if (!is_string($this->image_ratio_crop)) $this->image_ratio_crop = '';
							$this->image_ratio_crop = strtolower($this->image_ratio_crop);
							if (($this->image_src_x/$this->image_x) > ($this->image_src_y/$this->image_y)) {
								$this->image_dst_y = $this->image_y;
								$this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y));
								$ratio_crop = array();
								$ratio_crop['x'] = $this->image_dst_x - $this->image_x;
								if (strpos($this->image_ratio_crop, 'l') !== false) {
									$ratio_crop['l'] = 0;
									$ratio_crop['r'] = $ratio_crop['x'];
								} else if (strpos($this->image_ratio_crop, 'r') !== false) {
									$ratio_crop['l'] = $ratio_crop['x'];
									$ratio_crop['r'] = 0;
								} else {
									$ratio_crop['l'] = round($ratio_crop['x']/2);
									$ratio_crop['r'] = $ratio_crop['x'] - $ratio_crop['l'];
								}
								if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
							} else {
								$this->image_dst_x = $this->image_x;
								$this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x));
								$ratio_crop = array();
								$ratio_crop['y'] = $this->image_dst_y - $this->image_y;
								if (strpos($this->image_ratio_crop, 't') !== false) {
									$ratio_crop['t'] = 0;
									$ratio_crop['b'] = $ratio_crop['y'];
								} else if (strpos($this->image_ratio_crop, 'b') !== false) {
									$ratio_crop['t'] = $ratio_crop['y'];
									$ratio_crop['b'] = 0;
								} else {
									$ratio_crop['t'] = round($ratio_crop['y']/2);
									$ratio_crop['b'] = $ratio_crop['y'] - $ratio_crop['t'];
								}

								if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
							}
						} else if ($this->image_ratio_fill) {
							if (!is_string($this->image_ratio_fill)) $this->image_ratio_fill = '';
							$this->image_ratio_fill = strtolower($this->image_ratio_fill);
							if (($this->image_src_x/$this->image_x) < ($this->image_src_y/$this->image_y)) {
								$this->image_dst_y = $this->image_y;
								$this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y));
								$ratio_crop = array();
								$ratio_crop['x'] = $this->image_dst_x - $this->image_x;
								if (strpos($this->image_ratio_fill, 'l') !== false) {
									$ratio_crop['l'] = 0;
									$ratio_crop['r'] = $ratio_crop['x'];
								} else if (strpos($this->image_ratio_fill, 'r') !== false) {
									$ratio_crop['l'] = $ratio_crop['x'];
									$ratio_crop['r'] = 0;
								} else {
									$ratio_crop['l'] = round($ratio_crop['x']/2);
									$ratio_crop['r'] = $ratio_crop['x'] - $ratio_crop['l'];
								}
								
								if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
							} else {
								$this->image_dst_x = $this->image_x;
								$this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x));
								$ratio_crop = array();
								$ratio_crop['y'] = $this->image_dst_y - $this->image_y;
								if (strpos($this->image_ratio_fill, 't') !== false) {
									$ratio_crop['t'] = 0;
									$ratio_crop['b'] = $ratio_crop['y'];
								} else if (strpos($this->image_ratio_fill, 'b') !== false) {
									$ratio_crop['t'] = $ratio_crop['y'];
									$ratio_crop['b'] = 0;
								} else {
									$ratio_crop['t'] = round($ratio_crop['y']/2);
									$ratio_crop['b'] = $ratio_crop['y'] - $ratio_crop['t'];
								}
								
								if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
							}
						} else {
							if (($this->image_src_x/$this->image_x) > ($this->image_src_y/$this->image_y)) {
								$this->image_dst_x = $this->image_x;
								$this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x));
							} else {
								$this->image_dst_y = $this->image_y;
								$this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y));
							}
						}
					} else {
						
						$this->image_dst_x = $this->image_src_x;
						$this->image_dst_y = $this->image_src_y;
					}
				} else {
					
					$this->image_dst_x = $this->image_x;
					$this->image_dst_y = $this->image_y;
				}

				$image_dst = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);

				if ($gd_version >= 2) {
					$res = imagecopyresampled($image_dst, $image_src, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_src_x, $this->image_src_y);
				} else {
					$res = imagecopyresized($image_dst, $image_src, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_src_x, $this->image_src_y);
				}

			} else {
				// we only convert, so we link the dst image to the src image
				$image_dst = & $image_src;
			}
	
			// crop imag (and also crops if image_ratio_crop is used)
			if ((!empty($this->image_crop) || !is_null($ratio_crop))) {
				if (is_array($this->image_crop)) {
					$vars = $this->image_crop;
				} else {
					$vars = explode(' ', $this->image_crop);
				}
				if (sizeof($vars) == 4) {
					$ct = $vars[0]; $cr = $vars[1]; $cb = $vars[2]; $cl = $vars[3];
				} else if (sizeof($vars) == 2) {
					$ct = $vars[0]; $cr = $vars[1]; $cb = $vars[0]; $cl = $vars[1];
				} else {
					$ct = $vars[0]; $cr = $vars[0]; $cb = $vars[0]; $cl = $vars[0];
				} 
				if (strpos($ct, '%')>0) $ct = $this->image_dst_y * (str_replace('%','',$ct) / 100);
				if (strpos($cr, '%')>0) $cr = $this->image_dst_x * (str_replace('%','',$cr) / 100);
				if (strpos($cb, '%')>0) $cb = $this->image_dst_y * (str_replace('%','',$cb) / 100);
				if (strpos($cl, '%')>0) $cl = $this->image_dst_x * (str_replace('%','',$cl) / 100);
				if (strpos($ct, 'px')>0) $ct = str_replace('px','',$ct);
				if (strpos($cr, 'px')>0) $cr = str_replace('px','',$cr);
				if (strpos($cb, 'px')>0) $cb = str_replace('px','',$cb);
				if (strpos($cl, 'px')>0) $cl = str_replace('px','',$cl);
				$ct = (int) $ct;
				$cr = (int) $cr;
				$cb = (int) $cb;
				$cl = (int) $cl;
				// we adjust the cropping if we use image_ratio_crop
				if (!is_null($ratio_crop)) {
					if (array_key_exists('t', $ratio_crop)) $ct += $ratio_crop['t'];
					if (array_key_exists('r', $ratio_crop)) $cr += $ratio_crop['r'];
					if (array_key_exists('b', $ratio_crop)) $cb += $ratio_crop['b'];
					if (array_key_exists('l', $ratio_crop)) $cl += $ratio_crop['l'];
				}
				$this->log .= '- crop image : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . ' <br />';
				$this->image_dst_x = $this->image_dst_x - $cl - $cr;
				$this->image_dst_y = $this->image_dst_y - $ct - $cb;
				if ($this->image_dst_x < 1) $this->image_dst_x = 1;
				if ($this->image_dst_y < 1) $this->image_dst_y = 1;
				$tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
	
				// we copy the image into the recieving image
				imagecopy($tmp, $image_dst, 0, 0, $cl, $ct, $this->image_dst_x, $this->image_dst_y);
	
				// if we crop with negative margins, we have to make sure the extra bits are the right color, or transparent
				if ($ct < 0 || $cr < 0 || $cb < 0 || $cl < 0 ) {
					// use the background color if present
					if (!empty($this->image_background_color)) {
						sscanf($this->image_background_color, "#%2x%2x%2x", $red, $green, $blue);
						$fill = imagecolorallocate($tmp, $red, $green, $blue);       
					} else {
						$fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
					}
					// fills eventual negative margins
					if ($ct < 0) imagefilledrectangle($tmp, 0, 0, $this->image_dst_x, -$ct, $fill);
					if ($cr < 0) imagefilledrectangle($tmp, $this->image_dst_x + $cr, 0, $this->image_dst_x, $this->image_dst_y, $fill);
					if ($cb < 0) imagefilledrectangle($tmp, 0, $this->image_dst_y + $cb, $this->image_dst_x, $this->image_dst_y, $fill);
					if ($cl < 0) imagefilledrectangle($tmp, 0, 0, -$cl, $this->image_dst_y, $fill);
				}
	
				// we transfert tmp into image_dst
				$image_dst = $this->imagetransfer($tmp, $image_dst);
			}
	
			// flip image
			if ($gd_version >= 2 && !empty($this->image_flip)) {
				$this->image_flip = strtolower($this->image_flip);
				$this->log .= '- flip image : ' . $this->image_flip . '<br />';
				$tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
				for ($x = 0; $x < $this->image_dst_x; $x++) {
					for ($y = 0; $y < $this->image_dst_y; $y++){
						if (strpos($this->image_flip, 'v') !== false) {
							imagecopy($tmp, $image_dst, $this->image_dst_x - $x - 1, $y, $x, $y, 1, 1);
						} else {
							imagecopy($tmp, $image_dst, $x, $this->image_dst_y - $y - 1, $x, $y, 1, 1);
						}
					}
				}
				// we transfert tmp into image_dst
				$image_dst = $this->imagetransfer($tmp, $image_dst);  
			}
	
			// rotate image
			if ($gd_version >= 2 && is_numeric($this->image_rotate)) {
				if (!in_array($this->image_rotate, array(0, 90, 180, 270))) $this->image_rotate = 0;  
				if ($this->image_rotate != 0) {
					if ($this->image_rotate == 90 || $this->image_rotate == 270) {
						$tmp = $this->imagecreatenew($this->image_dst_y, $this->image_dst_x);
					} else {
						$tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
					}
					for ($x = 0; $x < $this->image_dst_x; $x++) {
						for ($y = 0; $y < $this->image_dst_y; $y++){
							if ($this->image_rotate == 90) {
								imagecopy($tmp, $image_dst, $y, $x, $x, $this->image_dst_y - $y - 1, 1, 1);
							} else if ($this->image_rotate == 180) {
								imagecopy($tmp, $image_dst, $x, $y, $this->image_dst_x - $x - 1, $this->image_dst_y - $y - 1, 1, 1);
							} else if ($this->image_rotate == 270) {
								imagecopy($tmp, $image_dst, $y, $x, $this->image_dst_x - $x - 1, $y, 1, 1);
							} else {
								imagecopy($tmp, $image_dst, $x, $y, $x, $y, 1, 1);
							}
						}
					}
					if ($this->image_rotate == 90 || $this->image_rotate == 270) {
						$t = $this->image_dst_y;
						$this->image_dst_y = $this->image_dst_x;
						$this->image_dst_x = $t;
					}
					// we transfert tmp into image_dst
					$image_dst = $this->imagetransfer($tmp, $image_dst);    
				}                        
			}
	
			// add color overlay
		   if ($gd_version >= 2 && (is_numeric($this->image_overlay_percent) && $this->image_overlay_percent > 0 && !empty($this->image_overlay_color))) {
				sscanf($this->image_overlay_color, "#%2x%2x%2x", $red, $green, $blue);
				$filter = imagecreatetruecolor($this->image_dst_x, $this->image_dst_y);
				$color = imagecolorallocate($filter, $red, $green, $blue);
				imagefilledrectangle($filter, 0, 0, $this->image_dst_x, $this->image_dst_y, $color);
				$this->imagecopymergealpha($image_dst, $filter, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_overlay_percent);
				imagedestroy($filter);                     
			}
	
			// add brightness, contrast and tint, turns to greyscale and inverts colors
			if ($gd_version >= 2 && ($this->image_negative || $this->image_greyscale || is_numeric($this->image_threshold)|| is_numeric($this->image_brightness) || is_numeric($this->image_contrast) || !empty($this->image_tint_color))) {
				if (!empty($this->image_tint_color)) sscanf($this->image_tint_color, "#%2x%2x%2x", $tint_red, $tint_green, $tint_blue);
				imagealphablending($image_dst, true);
				for($y=0; $y < $this->image_dst_y; $y++) {
					for($x=0; $x < $this->image_dst_x; $x++) {
						if ($this->image_greyscale) {
							$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
							$r = $g = $b = round((0.2125 * $pixel['red']) + (0.7154 * $pixel['green']) + (0.0721 * $pixel['blue']));    
							$color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
							imagesetpixel($image_dst, $x, $y, $color);
						}      
						if (is_numeric($this->image_threshold)) {
							$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
							$c = (round($pixel['red'] + $pixel['green'] + $pixel['blue']) / 3) - 127;
							$r = $g = $b = ($c > $this->image_threshold ? 255 : 0);    
							$color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
							imagesetpixel($image_dst, $x, $y, $color);
						}
						if (is_numeric($this->image_brightness)) {
							$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
							$r = max(min(round($pixel['red'] + (($this->image_brightness * 2))), 255), 0);
							$g = max(min(round($pixel['green'] + (($this->image_brightness * 2))), 255), 0);
							$b = max(min(round($pixel['blue'] + (($this->image_brightness * 2))), 255), 0);         
							$color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
							imagesetpixel($image_dst, $x, $y, $color);
						}
						if (is_numeric($this->image_contrast)) {
							$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
							$r = max(min(round(($this->image_contrast + 128) * $pixel['red'] / 128), 255), 0);
							$g = max(min(round(($this->image_contrast + 128) * $pixel['green'] / 128), 255), 0);
							$b = max(min(round(($this->image_contrast + 128) * $pixel['blue'] / 128), 255), 0);         
							$color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
							imagesetpixel($image_dst, $x, $y, $color);
						}
						if (!empty($this->image_tint_color)) {
							$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
							$r = min(round($tint_red * $pixel['red'] / 169), 255);
							$g = min(round($tint_green * $pixel['green'] / 169), 255);
							$b = min(round($tint_blue * $pixel['blue'] / 169), 255);        
							$color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
							imagesetpixel($image_dst, $x, $y, $color);
						}
						if (!empty($this->image_negative)) {
							$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
							$r = round(255 - $pixel['red']);
							$g = round(255 - $pixel['green']);
							$b = round(255 - $pixel['blue']);   
							$color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
							imagesetpixel($image_dst, $x, $y, $color);
						}
					}
				}
			}
	
			// adds a border
			if ($gd_version >= 2 && !empty($this->image_border)) {
				if (is_array($this->image_border)) {
					$vars = $this->image_border;
				} else {
					$vars = explode(' ', $this->image_border);
				}
				if (sizeof($vars) == 4) {
					$ct = $vars[0]; $cr = $vars[1]; $cb = $vars[2]; $cl = $vars[3];
				} else if (sizeof($vars) == 2) {
					$ct = $vars[0]; $cr = $vars[1]; $cb = $vars[0]; $cl = $vars[1];
				} else {
					$ct = $vars[0]; $cr = $vars[0]; $cb = $vars[0]; $cl = $vars[0];
				} 
				if (strpos($ct, '%')>0) $ct = $this->image_dst_y * (str_replace('%','',$ct) / 100);
				if (strpos($cr, '%')>0) $cr = $this->image_dst_x * (str_replace('%','',$cr) / 100);
				if (strpos($cb, '%')>0) $cb = $this->image_dst_y * (str_replace('%','',$cb) / 100);
				if (strpos($cl, '%')>0) $cl = $this->image_dst_x * (str_replace('%','',$cl) / 100);
				if (strpos($ct, 'px')>0) $ct = str_replace('px','',$ct);
				if (strpos($cr, 'px')>0) $cr = str_replace('px','',$cr);
				if (strpos($cb, 'px')>0) $cb = str_replace('px','',$cb);
				if (strpos($cl, 'px')>0) $cl = str_replace('px','',$cl);
				$ct = (int) $ct;
				$cr = (int) $cr;
				$cb = (int) $cb;
				$cl = (int) $cl;
				$this->image_dst_x = $this->image_dst_x + $cl + $cr;
				$this->image_dst_y = $this->image_dst_y + $ct + $cb;
				if (!empty($this->image_border_color)) sscanf($this->image_border_color, "#%2x%2x%2x", $red, $green, $blue);
				// we now create an image, that we fill with the border color
				$tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
				$background = imagecolorallocatealpha($tmp, $red, $green, $blue, 0);
				imagefilledrectangle($tmp, 0, 0, $this->image_dst_x, $this->image_dst_y, $background);
				// we then copy the source image into the new image, without merging so that only the border is actually kept
				imagecopy($tmp, $image_dst, $cl, $ct, 0, 0, $this->image_dst_x - $cr - $cl, $this->image_dst_y - $cb - $ct);
				// we transfert tmp into image_dst
				$image_dst = $this->imagetransfer($tmp, $image_dst);     
			}
	
			// add text
			if (!empty($this->image_text)) {
	
				if (!is_numeric($this->image_text_padding)) $this->image_text_padding = 0;
				if (!is_numeric($this->image_text_line_spacing)) $this->image_text_line_spacing = 0;
				if (!is_numeric($this->image_text_padding_x)) $this->image_text_padding_x = $this->image_text_padding;
				if (!is_numeric($this->image_text_padding_y)) $this->image_text_padding_y = $this->image_text_padding;
				$this->image_text_position = strtolower($this->image_text_position);
				$this->image_text_direction = strtolower($this->image_text_direction);
				$this->image_text_alignment = strtolower($this->image_text_alignment);
	
				// if the font is a string, we assume that we might want to load a font
				if (!is_numeric($this->image_text_font) && strlen($this->image_text_font) > 4 && substr(strtolower($this->image_text_font), -4) == '.gdf') {
	
					if (!$this->image_text_font = @imageloadfont($this->image_text_font)) $this->image_text_font = 5;
				}
	
				$text = explode("\n", $this->image_text);
				$char_width = imagefontwidth($this->image_text_font);
				$char_height = imagefontheight($this->image_text_font);
				$text_height = 0;
				$text_width = 0;
				$line_height = 0;
				$line_width = 0;
	
				foreach ($text as $k => $v) {
					if ($this->image_text_direction == 'v') {
						$h = ($char_width * strlen($v));
						if ($h > $text_height) $text_height = $h;
						$line_width = $char_height;
						$text_width += $line_width + ($k < (sizeof($text)-1) ? $this->image_text_line_spacing : 0);
					} else {
						$w = ($char_width * strlen($v));
						if ($w > $text_width) $text_width = $w;
						$line_height = $char_height;
						$text_height += $line_height + ($k < (sizeof($text)-1) ? $this->image_text_line_spacing : 0);
					}
				}
				$text_width  += (2 * $this->image_text_padding_x);  
				$text_height += (2 * $this->image_text_padding_y); 
				$text_x = 0;
				$text_y = 0;
				if (is_numeric($this->image_text_x)) {
					if ($this->image_text_x < 0) {
						$text_x = $this->image_dst_x - $text_width + $this->image_text_x;
					} else {
						$text_x = $this->image_text_x;
					}
				} else {
					if (strpos($this->image_text_position, 'r') !== false) {
						$text_x = $this->image_dst_x - $text_width;
					} else if (strpos($this->image_text_position, 'l') !== false) {
						$text_x = 0;
					} else {
						$text_x = ($this->image_dst_x - $text_width) / 2;
					}
				}
				if (is_numeric($this->image_text_y)) {
					if ($this->image_text_y < 0) {
						$text_y = $this->image_dst_y - $text_height + $this->image_text_y;
					} else {
						$text_y = $this->image_text_y;
					}
				} else {
					if (strpos($this->image_text_position, 'b') !== false) {
						$text_y = $this->image_dst_y - $text_height;
					} else if (strpos($this->image_text_position, 't') !== false) {
						$text_y = 0;
					} else {
						$text_y = ($this->image_dst_y - $text_height) / 2;
					}
				}
	
				// add a background, maybe transparent
				if (!empty($this->image_text_background)) {
					sscanf($this->image_text_background, "#%2x%2x%2x", $red, $green, $blue);
					if ($gd_version >= 2 && (is_numeric($this->image_text_background_percent)) && $this->image_text_background_percent >= 0 && $this->image_text_background_percent <= 100) {
						$filter = imagecreatetruecolor($text_width, $text_height);
						$background_color = imagecolorallocate($filter, $red, $green, $blue);
						imagefilledrectangle($filter, 0, 0, $text_width, $text_height, $background_color);
						$this->imagecopymergealpha($image_dst, $filter, $text_x, $text_y, 0, 0, $text_width, $text_height, $this->image_text_background_percent);
						imagedestroy($filter);
					} else {
						$background_color = imagecolorallocate($image_dst ,$red, $green, $blue);
						imagefilledrectangle($image_dst, $text_x, $text_y, $text_x + $text_width, $text_y + $text_height, $background_color);
					}
				}
	
				$text_x += $this->image_text_padding_x;
				$text_y += $this->image_text_padding_y;
				$t_width = $text_width - (2 * $this->image_text_padding_x);
				$t_height = $text_height - (2 * $this->image_text_padding_y);
				sscanf($this->image_text_color, "#%2x%2x%2x", $red, $green, $blue);
	
				// add the text, maybe transparent
				if ($gd_version >= 2 && (is_numeric($this->image_text_percent)) && $this->image_text_percent >= 0 && $this->image_text_percent <= 100) {
					if ($t_width < 0) $t_width = 0;
					if ($t_height < 0) $t_height = 0;
					$filter = $this->imagecreatenew($t_width, $t_height, false, true);
					$text_color = imagecolorallocate($filter ,$red, $green, $blue);
					foreach ($text as $k => $v) {
						if ($this->image_text_direction == 'v') {
							imagestringup($filter, 
										  $this->image_text_font, 
										  $k * ($line_width  + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), 
										  $text_height - (2 * $this->image_text_padding_y) - ($this->image_text_alignment == 'l' ? 0 : (($t_height - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))) , 
										  $v, 
										  $text_color);
						} else {
							imagestring($filter, 
										$this->image_text_font, 
										($this->image_text_alignment == 'l' ? 0 : (($t_width - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))), 
										$k * ($line_height  + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), 
										$v, 
										$text_color);
						}
					}
					$this->imagecopymergealpha($image_dst, $filter, $text_x, $text_y, 0, 0, $t_width, $t_height, $this->image_text_percent);
					imagedestroy($filter);
				} else {
					$text_color = imageColorAllocate($image_dst ,$red, $green, $blue);
					foreach ($text as $k => $v) {
						if ($this->image_text_direction == 'v') {
							imagestringup($image_dst, 
										  $this->image_text_font, 
										  $text_x + $k * ($line_width  + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), 
										  $text_y + $text_height - (2 * $this->image_text_padding_y) - ($this->image_text_alignment == 'l' ? 0 : (($t_height - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))), 
										  $v, 
										  $text_color);
						} else {
							imagestring($image_dst, 
										$this->image_text_font, 
										$text_x + ($this->image_text_alignment == 'l' ? 0 : (($t_width - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))), 
										$text_y + $k * ($line_height  + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)), 
										$v, 
										$text_color);
						}
					}
				}
			}
	
			switch($this->image_convert) {
				case 'gif':
					// if the image is true color, we convert it to a palette
					if (imageistruecolor($image_dst)) {
						// creates a black and white mask
						$mask = array(array());
						for ($x = 0; $x < $this->image_dst_x; $x++) {
							for ($y = 0; $y < $this->image_dst_y; $y++) {
								$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));      
								$mask[$x][$y] = $pixel['alpha'];
							}
						}    
						sscanf($this->image_default_color, "#%2x%2x%2x", $red, $green, $blue);
						// first, we merge the image with the background color, so we know which colors we will have
						for ($x = 0; $x < $this->image_dst_x; $x++) {
							for ($y = 0; $y < $this->image_dst_y; $y++) {
								if ($mask[$x][$y] > 0){
									// we have some transparency. we combine the color with the default color
									$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
									$alpha = ($mask[$x][$y] / 127);
									$pixel['red'] = round(($pixel['red'] * (1 -$alpha) + $red * ($alpha)));
									$pixel['green'] = round(($pixel['green'] * (1 -$alpha) + $green * ($alpha)));
									$pixel['blue'] = round(($pixel['blue'] * (1 -$alpha) + $blue * ($alpha)));
									$color = imagecolorallocate($image_dst, $pixel['red'], $pixel['green'], $pixel['blue']);
									imagesetpixel($image_dst, $x, $y, $color);
								}
							}
						}
						// transfrom the true color image into palette, with it merged default color in
						// we will have the best color possible, including the background
						if (empty($this->image_background_color)) {
							imagetruecolortopalette($image_dst, true, 255);
							$transparency = imagecolorallocate($image_dst, 254, 1, 253);
							imagecolortransparent($image_dst, $transparency);
							// make the transparent areas transparent
							for ($x = 0; $x < $this->image_dst_x; $x++) {
								for ($y = 0; $y < $this->image_dst_y; $y++) {
									// we test wether we have enough opacity to justify keeping the color
									if ($mask[$x][$y] > 120) imagesetpixel($image_dst, $x, $y, $transparency);
								}
							}
						}
						unset($mask);
					}
					break;
				case 'jpg':
				case 'bmp':
						sscanf($this->image_default_color, "#%2x%2x%2x", $red, $green, $blue);
						$transparency = imagecolorallocate($image_dst, $red, $green, $blue);
						// make the transaparent areas transparent
						for ($x = 0; $x < $this->image_dst_x; $x++) {
							for ($y = 0; $y < $this->image_dst_y; $y++) {
								// we test wether we have some transparency, in which case we will merge the colors
								$pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
								if ($pixel['alpha'] == 127) {
									// we have full transparency. we make the pixel transparent
									imagesetpixel($image_dst, $x, $y, $transparency);
								} else if ($pixel['alpha'] > 0) {
									// we have some transparency. we combine the color with the default color
									$alpha = ($pixel['alpha'] / 127);
									$pixel['red'] = round(($pixel['red'] * (1 -$alpha) + $red * ($alpha)));
									$pixel['green'] = round(($pixel['green'] * (1 -$alpha) + $green * ($alpha)));
									$pixel['blue'] = round(($pixel['blue'] * (1 -$alpha) + $blue * ($alpha)));
									$color = imagecolorclosest($image_dst, $pixel['red'], $pixel['green'], $pixel['blue']);
									imagesetpixel($image_dst, $x, $y, $color);
								}
							}
						}
					break;
			}
	
			switch($t = $this->image_convert) {
				case 'jpeg':
				case 'jpg':
					if (!$return_mode) {
						$result = imagejpeg($image_dst, $this->file_dst_pathname, $this->jpeg_quality);
					} else {
						ob_start();        
						$result = imagejpeg($image_dst, '', $this->jpeg_quality);
						$return_content = ob_get_contents();
						ob_end_clean();
					}
					if (!$result) {
						$this->error = 'file_create';
						return false;
					}
					break;
				case 'png':
					imagealphablending( $image_dst, false );
					imagesavealpha( $image_dst, true );
				case 'gif':
				case 'bmp':
					$f = "image$t";
					if (!$return_mode) {
						$result = $f($image_dst, $this->file_dst_pathname);
					} else {
						ob_start();        
						$result = $f($image_dst);
						$return_content = ob_get_contents();
						ob_end_clean();
					}
					if (!$result) {
						$this->error = 'file_create';
						return false;
					}
					break;
				default:
					$this->error = 'no_conversion_type';
					return false;
			}
			
			if (is_resource($image_src)) imagedestroy($image_src);
			if (is_resource($image_dst)) imagedestroy($image_dst);
			
			$this->processed = true;
			return $return_content;
		}
	}
	
	/**
	 * Opens a BMP image
	 *
	 * This function has been written by DHKold, and is used with permission of the author
	 *
	 * @access public
	 */
	function imagecreatefrombmp($filename) {
		if (! $f1 = fopen($filename,"rb")) return false;

		$file = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
		if ($file['file_type'] != 19778) return false;

		$bmp = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
					  '/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
					  '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
		$bmp['colors'] = pow(2,$bmp['bits_per_pixel']);
		if ($bmp['size_bitmap'] == 0) $bmp['size_bitmap'] = $file['file_size'] - $file['bitmap_offset'];
		$bmp['bytes_per_pixel'] = $bmp['bits_per_pixel']/8;
		$bmp['bytes_per_pixel2'] = ceil($bmp['bytes_per_pixel']);
		$bmp['decal'] = ($bmp['width']*$bmp['bytes_per_pixel']/4);
		$bmp['decal'] -= floor($bmp['width']*$bmp['bytes_per_pixel']/4);
		$bmp['decal'] = 4-(4*$bmp['decal']);
		if ($bmp['decal'] == 4) $bmp['decal'] = 0;

		$palette = array();
		if ($bmp['colors'] < 16777216) {
			$palette = unpack('V'.$bmp['colors'], fread($f1,$bmp['colors']*4));
		}

		$im = fread($f1,$bmp['size_bitmap']);
		$vide = chr(0);

		$res = imagecreatetruecolor($bmp['width'],$bmp['height']);
		$P = 0;
		$Y = $bmp['height']-1;
		while ($Y >= 0) {
			$X=0;
			while ($X < $bmp['width']) {
				if ($bmp['bits_per_pixel'] == 24)
					$color = unpack("V",substr($im,$P,3).$vide);
				elseif ($bmp['bits_per_pixel'] == 16) { 
					$color = unpack("n",substr($im,$P,2));
					$color[1] = $palette[$color[1]+1];
				} elseif ($bmp['bits_per_pixel'] == 8) { 
					$color = unpack("n",$vide.substr($im,$P,1));
					$color[1] = $palette[$color[1]+1];
				} elseif ($bmp['bits_per_pixel'] == 4) {
					$color = unpack("n",$vide.substr($im,floor($P),1));
					if (($P*2)%2 == 0) $color[1] = ($color[1] >> 4) ; else $color[1] = ($color[1] & 0x0F);
					$color[1] = $palette[$color[1]+1];
				} elseif ($bmp['bits_per_pixel'] == 1)  {
					$color = unpack("n",$vide.substr($im,floor($P),1));
					if     (($P*8)%8 == 0) $color[1] =  $color[1]        >>7;
					elseif (($P*8)%8 == 1) $color[1] = ($color[1] & 0x40)>>6;
					elseif (($P*8)%8 == 2) $color[1] = ($color[1] & 0x20)>>5;
					elseif (($P*8)%8 == 3) $color[1] = ($color[1] & 0x10)>>4;
					elseif (($P*8)%8 == 4) $color[1] = ($color[1] & 0x8)>>3;
					elseif (($P*8)%8 == 5) $color[1] = ($color[1] & 0x4)>>2;
					elseif (($P*8)%8 == 6) $color[1] = ($color[1] & 0x2)>>1;
					elseif (($P*8)%8 == 7) $color[1] = ($color[1] & 0x1);
					$color[1] = $palette[$color[1]+1];
				} else
					return FALSE;
				imagesetpixel($res,$X,$Y,$color[1]);
				$X++;
				$P += $bmp['bytes_per_pixel'];
			}
			$Y--;
			$P+=$bmp['decal'];
		}
		fclose($f1);
		return $res;
	}
	
	/**
	 * Saves a BMP image
	 *
	 * This function has been published on the PHP website, and can be used freely
	 *
	 * @access public
	 */    
	function imagebmp(&$im, $filename = "") {

		if (!$im) return false;
		$w = imagesx($im);
		$h = imagesy($im);
		$result = '';

		// if the image is not true color, we convert it first
		if (!imageistruecolor($im)) {
			$tmp = imagecreatetruecolor($w, $h); 
			imagecopy($tmp, $im, 0, 0, 0, 0, $w, $h); 
			imagedestroy($im);
			$im = & $tmp;   
		}

		$biBPLine = $w * 3;
		$biStride = ($biBPLine + 3) & ~3;
		$biSizeImage = $biStride * $h;
		$bfOffBits = 54;
		$bfSize = $bfOffBits + $biSizeImage;

		$result .= substr('BM', 0, 2);
		$result .=  pack ('VvvV', $bfSize, 0, 0, $bfOffBits);
		$result .= pack ('VVVvvVVVVVV', 40, $w, $h, 1, 24, 0, $biSizeImage, 0, 0, 0, 0);

		$numpad = $biStride - $biBPLine;
		for ($y = $h - 1; $y >= 0; --$y) {
			for ($x = 0; $x < $w; ++$x) {
				$col = imagecolorat ($im, $x, $y);
				$result .=  substr(pack ('V', $col), 0, 3);
			}
			for ($i = 0; $i < $numpad; ++$i)
				$result .= pack ('C', 0);
		}

		if($filename==""){
			echo $result;
		} else {
			$file = fopen($filename, "wb");
			fwrite($file, $result);
			fclose($file);
		}
		return true;        
	}

